package com.stars.easyms.demo.rest.service.sentinel;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.stars.easyms.demo.rest.dto.input.sentinel.SentinelDemo2Input;
import com.stars.easyms.demo.rest.dto.output.sentinel.SentinelDemo2Output;
import com.stars.easyms.demo.util.DemoThreadUtil;
import com.stars.easyms.rest.RestService;
import com.stars.easyms.base.util.MessageFormatUtil;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * sentinel手动注入流控规则
 *
 * @author guoguifang
 * @date 2018-04-23 13:54
 * @since 1.0.0
 */
@Service
public class SentinelDemo2Service implements RestService<SentinelDemo2Input, SentinelDemo2Output> {

    private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(50);

    private static final String RESOURCE_NAME = SentinelDemo2Service.class.getSimpleName();

    @Override
    public SentinelDemo2Output execute(SentinelDemo2Input input) {
        defineFlowRules(input);
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger blockCount = new AtomicInteger(0);
        List<Future<Boolean>> futureList = new ArrayList<>();
        for (int i = 0; i < input.getTimes(); i++) {
            // 循环times次，如果阈值达到则限流抛出BlockException
            futureList.add(DemoThreadUtil.submit(EXECUTOR_SERVICE, () -> {
                try (Entry entry = SphU.entry(RESOURCE_NAME)) {
                    Thread.sleep(20);
                    System.out.println(RESOURCE_NAME);
                    successCount.incrementAndGet();
                } catch (BlockException e1) {
                    blockCount.incrementAndGet();
                } catch (Throwable e1) {
                    e1.printStackTrace();
                }
                return Boolean.TRUE;
            }));
        }
        DemoThreadUtil.getFutureResult(futureList);
        SentinelDemo2Output output = new SentinelDemo2Output();
        System.out.println(MessageFormatUtil.format("Rest Service[{}], param[{}]!", this.getClass().getSimpleName(), input));
        output.setSuccessCount(successCount.get());
        output.setBlockCount(blockCount.get());
        return null;
    }

    private void defineFlowRules(SentinelDemo2Input input) {
        List<FlowRule> rules = new ArrayList<>();
        // 定义该规则为流控规则
        FlowRule rule = new FlowRule();
        // 定义资源名称
        rule.setResource(RESOURCE_NAME);
        // 定义流控阈值类型(0: threadCount, 1: QPS)
        rule.setGrade(input.getGrade());
        // 定义单机阈值.
        rule.setCount(input.getCount());
        // 定义流控模式(0: 直接(默认), 1: 关联, 2: 链路)
        rule.setStrategy(input.getStrategy());
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

}


